package com.yyfax.pay.depository.service.inner.impl;

import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.yyfax.commons.json.FastJsonUtil;
import com.yyfax.commons.lang.DateUtil;
import com.yyfax.framework.common.Log;
import com.yyfax.framework.yyfax.CryptUtil;
import com.yyfax.framework.yyfax.enums.UserTypeEnum;
import com.yyfax.framework.yyfax.enums.YesNoEnum;
import com.yyfax.pay.common.enums.FuiouBusiTypeEnum;
import com.yyfax.pay.common.enums.FuiouDepositRspCodeEnum;
import com.yyfax.pay.common.enums.FuiouDepositStateEnum;
import com.yyfax.pay.common.exception.PayException;
import com.yyfax.pay.common.exception.PayExceptionCode;
import com.yyfax.pay.common.model.to.YYPayApiReq2;
import com.yyfax.pay.common.model.vo.AmountRspParamsVO;
import com.yyfax.pay.common.model.vo.BackResultFormVO;
import com.yyfax.pay.common.model.vo.PayRspCodeVO;
import com.yyfax.pay.common.model.vo.RedirectFormVO;
import com.yyfax.pay.common.util.FuiouIdUtils;
import com.yyfax.pay.depository.dao.FuiouChargeDao;
import com.yyfax.pay.depository.dao.FuiouChargeTransferDao;
import com.yyfax.pay.depository.domain.FuiouCharge;
import com.yyfax.pay.depository.domain.FuiouChargeTransfer;
import com.yyfax.pay.depository.service.inner.ChargeInnerService;
import com.yyfax.pay.depository.service.inner.FuiouDepositCommonService;
import com.yyfax.pay.depository.vo.FuiouChargeTransferVO;
import com.yyfax.pay.depository.vo.FuiouChargeVO;
import com.yyfax.pay.order.service.PayCommonService;
import com.yyfax.pay.third.facade.fuioudeposit.FuiouDepositService;
import com.yyfax.pay.third.facade.fuioudeposit.FuiouSignService;
import com.yyfax.pay.third.model.to.fuioudeposit.BasePlainXMLRsp;
import com.yyfax.pay.third.model.to.fuioudeposit.ChargeNotifyReq;
import com.yyfax.pay.third.model.to.fuioudeposit.EBankChargeBackReq;
import com.yyfax.pay.third.model.to.fuioudeposit.FuiouEbankFormVO;
import com.yyfax.pay.third.model.to.fuioudeposit.FuiouTransferChargeFormVO;
import com.yyfax.pay.third.model.to.fuioudeposit.ResultXMLRsp;
import com.yyfax.pay.third.model.to.fuioudeposit.TransferChargeBackReq;
import com.yyfax.pay.third.model.to.fuioudeposit.xml.TransferChargePlain;
import com.yyfax.pay.vo.depository.ChargeBaseReq;
import com.yyfax.pay.vo.depository.ChargeProtocolSignRechargeReq;
import com.yyfax.pay.vo.depository.EBankChargeReq;
import com.yyfax.pay.vo.depository.EntrustChargeReq;
import com.yyfax.pay.vo.depository.QuickChargeSendSmsReq;
import com.yyfax.pay.vo.depository.TransferChargeReq;
import com.yyfax.pay.vo.depository.TransferChargeRsp;

@Service
public class ChargeInnerServiceImpl implements ChargeInnerService {

	private Logger logger = LoggerFactory.getLogger(getClass());

	@Resource
	private FuiouIdUtils fuiouIdUtils;

	@Resource
	private FuiouChargeDao fuiouChargeDao;

	@Resource
	private FuiouChargeTransferDao fuiouChargeTransferDao;

	@Resource
	private FuiouDepositService fuiouDepositService;

	@Resource
	private FuiouDepositCommonService fuiouDepositCommonService;

	@Resource
	private PayCommonService payCommonService;

	@Resource
	private FuiouSignService fuiouSignService;

	@Override
	public FuiouChargeVO saveCharge(String merchantCode, ChargeBaseReq params) throws Exception {
		final String op = "ChargeInnerServiceImpl.saveCharge";

		// FuiouCharge po = new FuiouCharge();

		// 业务类型
		// FuiouBusiTypeEnum busiType = null;
		// 银行编号，网银充值的参数
		// String bankCode = "";
		// 回跳地址，网银网关充值的参数
		// String backUrl = "";
		// String pageBackUrl = "";
		// 主体类型，默认为个人
		// String subjectType = UserTypeEnum.NATURAL_PERSON.getValue();
		// 手机号，快捷充值
		// String phone = "";
		// 银行卡，快捷充值
		// String cardNoCip = "";

		// if (params instanceof EBankChargeReq) {
		// busiType = FuiouBusiTypeEnum.EBANK_CHARGE;
		// bankCode = ((EBankChargeReq) params).getBankCode();
		// subjectType = ((EBankChargeReq) params).getSubjectType();
		// backUrl = ((EBankChargeReq) params).getBackUrl();
		// pageBackUrl = ((EBankChargeReq) params).getPageBackUrl();
		// } else if (params instanceof QuickChargeSendSmsReq) {
		// busiType = FuiouBusiTypeEnum.QUICK_CHARGE;
		// phone = ((QuickChargeSendSmsReq) params).getPhone();
		// cardNoCip = CryptUtil.encrypt(((QuickChargeSendSmsReq) params).getCardNo());
		// } else if (params instanceof EntrustChargeReq) {
		// busiType = FuiouBusiTypeEnum.ENTRUST_CHARGE;
		// backUrl = ((EntrustChargeReq) params).getBackUrl();
		// } else if (params instanceof TransferChargeReq) {
		// busiType = FuiouBusiTypeEnum.TRANSFER_CHARGE;
		// subjectType = ((TransferChargeReq) params).getSubjectType();
		// } else if (params instanceof TransferChargeReq) {
		//
		// } else {
		// throw PayExceptionCode.ERROR_ILL_PARAMETER.expMsg("无效的ChargeBaseReq子类型");
		// }

		// po.setBusiId(fuiouIdUtils.generateBusiId(busiType, merchantCode));
		// po.setType(busiType.getValue());
		//
		// po.setMerchantCode(merchantCode);
		// po.setOrderId(params.getOrderId());
		// po.setOrderTime(params.getOrderTime());
		// po.setUserId(params.getUserId());
		// po.setLoginId(params.getLoginId());
		// po.setAmount(params.getAmount());
		// po.setSubjectType(subjectType);
		// po.setBankCode(bankCode); // 该银行编号为支付模块全局统一规范的，网银请求的时候，需要重新拼装富友网银的银行代码
		// po.setPhone(phone);
		// po.setCardNoCip(cardNoCip);
		// po.setPageBackUrl(pageBackUrl);
		// po.setBackUrl(backUrl);
		// po.setNotifyUrl(params.getNotifyUrl());
		// po.setState(FuiouDepositStateEnum.INI.getValue());
		// po.setTerminal(params.getTerminal());
		// String nowTime = DateUtil.getCurrentDateTime();
		// po.setCreateTime(nowTime);
		// po.setUpdateTime(nowTime);
		// po.setRemark(params.getRemark());

		FuiouCharge po = buildFuiouCharge(merchantCode, params);

		try {
			fuiouChargeDao.insert(po);
		} catch (DuplicateKeyException e) {
			logger.warn(Log.op(op).msg("保存订单信息主键冲突,订单已存在").kv("merchantCode", merchantCode).kv("orderId", params.getOrderId()).toString(), e);
			// 主键冲突，做幂等
			po = fuiouChargeDao.selectByMerchantCodeAndOrderId(merchantCode, params.getOrderId());
			if (po == null) {
				logger.error(Log.op(op).msg("保存订单信息主键冲突,查询订单的不存在").kv("merchantCode", merchantCode).kv("orderId", params.getOrderId()).toString());
				throw PayExceptionCode.ORDER_NOT_FOUND.exp();
			}
		}

		return FuiouChargeVO.newInstantce(po);
	}

	/**
	 * 构建充值订单
	 * 
	 * @author buyi
	 * @date 2018-06-20 11:45:36
	 * @since v2.2.2
	 * @param merchantCode
	 * @param params
	 * @return
	 * @throws Exception
	 */
	private FuiouCharge buildFuiouCharge(String merchantCode, ChargeBaseReq params) throws Exception {
		FuiouCharge fuiouCharge = new FuiouCharge();
		// 设置用户主体类型为个人
		fuiouCharge.setSubjectType(UserTypeEnum.NATURAL_PERSON.getValue());

		FuiouBusiTypeEnum busiType = null;

		if (params instanceof EBankChargeReq) {
			// 网银充值

			busiType = FuiouBusiTypeEnum.EBANK_CHARGE;
			EBankChargeReq eBankChargeReq = (EBankChargeReq) params;

			// 该银行编号为支付模块全局统一规范的，网银请求的时候，需要重新拼装富友网银的银行代码
			fuiouCharge.setBankCode(eBankChargeReq.getBankCode());
			fuiouCharge.setSubjectType(eBankChargeReq.getSubjectType());
			fuiouCharge.setBackUrl(eBankChargeReq.getBackUrl());
			fuiouCharge.setPageBackUrl(eBankChargeReq.getPageBackUrl());
		} else if (params instanceof QuickChargeSendSmsReq) {
			// 快捷充值

			busiType = FuiouBusiTypeEnum.QUICK_CHARGE;
			QuickChargeSendSmsReq quickChargeSendSmsReq = (QuickChargeSendSmsReq) params;

			fuiouCharge.setPhone(quickChargeSendSmsReq.getPhone());
			fuiouCharge.setCardNoCip(CryptUtil.encrypt(quickChargeSendSmsReq.getCardNo()));
		} else if (params instanceof EntrustChargeReq) {
			// 委托充值

			busiType = FuiouBusiTypeEnum.ENTRUST_CHARGE;
			EntrustChargeReq entrustChargeReq = (EntrustChargeReq) params;

			fuiouCharge.setBackUrl(entrustChargeReq.getBackUrl());
		} else if (params instanceof TransferChargeReq) {
			// 转账充值

			busiType = FuiouBusiTypeEnum.TRANSFER_CHARGE;
			TransferChargeReq transferChargeReq = (TransferChargeReq) params;

			fuiouCharge.setSubjectType(transferChargeReq.getSubjectType());

		} else if (params instanceof ChargeProtocolSignRechargeReq) {
			// 协议充值

			busiType = FuiouBusiTypeEnum.PROTOCOL_CHARGE;
			ChargeProtocolSignRechargeReq chargeProtocolSignRechargeReq = (ChargeProtocolSignRechargeReq) params;

			fuiouCharge.setSubjectType(chargeProtocolSignRechargeReq.getSubjectType());

		} else {
			throw PayExceptionCode.ERROR_ILL_PARAMETER.expMsg("无效的ChargeBaseReq子类型");
		}

		fuiouCharge.setType(busiType.getValue());
		fuiouCharge.setBusiId(fuiouIdUtils.generateBusiId(busiType, merchantCode));
		fuiouCharge.setMerchantCode(merchantCode);
		fuiouCharge.setOrderId(params.getOrderId());
		fuiouCharge.setOrderTime(params.getOrderTime());
		fuiouCharge.setUserId(params.getUserId());
		fuiouCharge.setLoginId(params.getLoginId());
		fuiouCharge.setAmount(params.getAmount());
		fuiouCharge.setNotifyUrl(params.getNotifyUrl());
		fuiouCharge.setState(FuiouDepositStateEnum.INI.getValue());
		fuiouCharge.setTerminal(params.getTerminal());
		// String nowTime = DateUtil.getCurrentDateTime();
		// fuiouCharge.setCreateTime(nowTime);
		// fuiouCharge.setUpdateTime(nowTime);
		fuiouCharge.setRemark(params.getRemark());

		return fuiouCharge;
	}

	@Override
	public RedirectFormVO<FuiouEbankFormVO> getEbankForm(FuiouChargeVO vo) throws Exception {
		return fuiouDepositService.getEbankForm(vo.getPo());
	}

	@Override
	public FuiouCharge parseEbankBackResult(String merchantCode, EBankChargeBackReq req) {
		String op = "ChargeInnerServiceImpl.parseEbankBackResult";

		// 解析请求的合法
		boolean isSign = fuiouDepositService.checkSignRspResult(merchantCode, req, req.getSignature());
		if (!isSign) {
			throw PayExceptionCode.ERROR_SIGN_FAIL.exp();
		}

		// 根据业务主键查询订单信息
		FuiouCharge po = fuiouChargeDao.selectByBusiId(req.getMchnt_txn_ssn());
		if (po == null) {
			logger.error(Log.op(op).msg("富友网银充值同步结果回调，订单不存在").kv("busiId", req.getMchnt_txn_ssn()).toString());
			throw PayExceptionCode.ERROR_ILL_PARAMETER.exp();
		}

		FuiouChargeVO vo = FuiouChargeVO.newInstantce(po);
		if (vo.isResult()) {
			// 如果订单是受理成功则直接返回
			logger.info(Log.op(op).msg("富友网银充值同步结果回调，订单已经出结果，不再处理").kv("busiId", po.getBusiId()).toString());
			return vo.getPo();
		}

		// 判断同步请求金额和订单金额不一致
		boolean isExpAmount = false;
		if (req.getAmt() != po.getAmount().longValue()) {
			// 请求订单金额不一致
			isExpAmount = true;
			logger.error(Log.op(op).msg("富友网银充值同步结果回调,请求金额和订单金额不一致").kv("busiId", po.getBusiId()).kv("orderAmount", po.getAmount())
					.kv("reqAmount", req.getAmt()).toString());
		}

		// 解析富友返回响应码
		FuiouDepositStateEnum state = FuiouDepositStateEnum.FAIL;
		PayRspCodeVO payRspCode = fuiouDepositService.converToPayRspCode(req.getResp_code());
		int rspCode = payRspCode.getCode();
		String rspMsg = payRspCode.getDesc();
		if (PayExceptionCode.SUCCESS.isCode(payRspCode.getCode())) {
			state = FuiouDepositStateEnum.SUCCESS;

			// 如果响应结果和订单金额不一致，则返回成功的异常响应码
			if (isExpAmount) {
				rspCode = PayExceptionCode.SUCCESS_EXCEPTION.getCode();
				rspMsg = PayExceptionCode.SUCCESS_EXCEPTION.getDesc();
			}

		} else if (PayExceptionCode.WARN_REQ_TIME_OUT.isCode(payRspCode.getCode()) || PayExceptionCode.TO_CONFIRM.isCode(payRspCode.getCode())) {
			// 如果响应状态为超时,或者待确认，则更新订单状态为处理中
			state = FuiouDepositStateEnum.DEALING;
			try {
				// 如果超时生成超时查询任务
				fuiouDepositCommonService.saveQueryTask(merchantCode, po.getBusiId(), FuiouBusiTypeEnum.CHARGE_QUERY);
			} catch (Exception e) {
				logger.error("生成充值超时查询任务异常，busiId:" + po.getBusiId(), e);
			}
		}

		// 订单存在web返回状态是超时的，异步通知是成功的场景
		List<String> origStates = Lists.newArrayList(FuiouDepositStateEnum.INI.getValue(), FuiouDepositStateEnum.DEALING.getValue());
		int i = fuiouChargeDao.updateStateFromOrigStates(po.getBusiId(), state.getValue(), rspCode, rspMsg, DateUtil.getCurrentDateTime(),
				origStates);
		// 如果更新状态没有命中，则状态可能是并发,则重新查询一次订单信息
		if (i <= 0) {
			logger.warn(Log.op(op).msg("富友网银充值同步结果回调,更新状态没有成功。").kv("busiId", po.getBusiId()).kv("toState", state.getValue())
					.kv("origState", po.getState()).toString());
			return fuiouChargeDao.selectByBusiId(req.getMchnt_txn_ssn());
		}

		po.setRspCode(rspCode);
		po.setRspMsg(rspMsg);
		po.setState(state.getValue());

		// 生成一个同步结果的异步通知
		generateBackNotifyTask(po, rspCode, rspMsg);

		return po;
	}

	@Override
	public RedirectFormVO<BackResultFormVO> getRouteForm(FuiouCharge po) throws Exception {
		if (po == null) {
			throw PayExceptionCode.ERROR_ILL_PARAMETER.expMsg("po不能为空");
		}

		// 封装同步通知参数，并返回
		AmountRspParamsVO params = new AmountRspParamsVO();
		params.setOrderId(po.getOrderId());
		params.setRspCode(po.getRspCode());
		params.setRspMsg(po.getRspMsg());
		params.setBusiId(po.getBusiId());
		params.setAmount(po.getAmount());

		BackResultFormVO form = new BackResultFormVO();
		form.setMerchantCode(po.getMerchantCode());
		form.setSign(payCommonService.getSign(po.getMerchantCode(), params));
		form.setParams(JSON.toJSONString(params));

		return RedirectFormVO.newInstance(po.getPageBackUrl(), form);
	}

	@Override
	public String parseChargeNotifyResult(String merchantCode, ChargeNotifyReq req) {
		final String op = "ChargeInnerServiceImpl.parseChargeNotifyResult";
		// 解析请求的合法
		boolean isSign = fuiouDepositService.checkSignRspResult(merchantCode, req, req.getSignature());
		if (!isSign) {
			throw PayExceptionCode.ERROR_SIGN_FAIL.exp();
		}

		// 根据业务主键查询订单信息
		FuiouCharge po = fuiouChargeDao.selectByBusiId(req.getMchnt_txn_ssn());
		if (po == null) {
			logger.error(Log.op(op).msg("充值异步回调发现订单状不存在，需要人工介入").kv("busiId", req.getMchnt_txn_ssn()).toString());
			return buildNotifyRsp(merchantCode, req);
		}

		logger.info(Log.op(op).msg("收到充值成功通知").kv("busiId", po.getBusiId()).kv("orderId", po.getOrderId()).toString());

		// 转账充值不通知
		if (FuiouBusiTypeEnum.TRANSFER_CHARGE.isValue(po.getType())) {
			// 如果充值类型为转账通知,则必须通知
			logger.info(Log.op(op).msg("充值结果通知 | 转账充值").kv("ChargeNotifyReq", req).toString());
			parseResult(FuiouDepositRspCodeEnum.SUCCESS.getValue(), "成功", req.getAmt(), po);
			return buildNotifyRsp(merchantCode, req);
		}

		if (po.getAmount().longValue() != req.getAmt()) {
			logger.error(Log.op(op).msg("充值异步回调发现订单金额和通知金额不一致，需要人工介入").kv("busiId", po.getBusiId()).kv("orderAmount", po.getAmount())
					.kv("reqAmount", req.getAmt()).toString());
		}

		// 异步通知只做金额检验和状态校验
		if (!FuiouDepositStateEnum.SUCCESS.isValue(po.getState())) {
			logger.error(Log.op(op).msg("充值异步回调发现订单状态不是成功状态，需要人工介入").kv("busiId", po.getBusiId()).kv("state", po.getState()).toString());
		}

		return buildNotifyRsp(merchantCode, req);
	}

	/**
	 * 封装响应富友异步结果异步回调的响应报文
	 * 
	 * @author buyi
	 * @date 2017-09-27 11:09:01
	 * @since v2.0.0
	 * @param merchantCode
	 * @param req
	 * @return
	 */
	private String buildNotifyRsp(String merchantCode, ChargeNotifyReq req) {
		// 封装异步响应
		BasePlainXMLRsp plain = new BasePlainXMLRsp();
		plain.setRspCode(FuiouDepositRspCodeEnum.SUCCESS.getValue());
		plain.setMerchantCode(req.getMchnt_cd());
		plain.setBusiId(req.getMchnt_txn_ssn());

		ResultXMLRsp rsp = new ResultXMLRsp();
		rsp.setPlain(plain);
		rsp.setSign(fuiouSignService.sign(merchantCode, plain.toXml()));

		return rsp.toXml();
	}

	/**
	 * 生成同步结果的异步通知任务
	 * 
	 * @author buyi
	 * @date 2017-09-21 11:46:15
	 * @since v2.0.0
	 * @param po
	 * @param code
	 * @throws Exception
	 */
	@Async
	private void generateBackNotifyTask(final FuiouCharge po, int rspCode, String rspMsg) {
		final String op = "ChargeInnerServiceImpl.generateBackNotifyTask";
		logger.info(Log.op(op).msg("生成通知任务").kv("busiId", po.getBusiId()).toString());
		try {
			AmountRspParamsVO params = new AmountRspParamsVO();
			params.setOrderId(po.getOrderId());
			params.setRspCode(rspCode);
			params.setRspMsg(rspMsg);
			params.setBusiId(po.getBusiId());
			params.setAmount(po.getAmount());

			YYPayApiReq2<AmountRspParamsVO> req = new YYPayApiReq2<>();
			req.setMerchantCode(po.getMerchantCode());
			req.setSign(payCommonService.getSign(po.getMerchantCode(), params));
			req.setParams(params);

			fuiouDepositCommonService.saveNotifyTask(po.getMerchantCode(), po.getOrderId(), po.getBusiId(), FuiouBusiTypeEnum.parse(po.getType()),
					po.getBackUrl(), FastJsonUtil.toJson(req), null, null);
		} catch (Exception e) {
			logger.error(Log.op("ChargeInnerServiceImpl.generateNotifyTask").msg("封装同步结果异步通知任务异常").kv("FuiouCharge", po).toString(), e);
		}
	}

	/**
	 * 生成通知任务
	 * 
	 * @author buyi
	 * @date 2018-03-29 09:48:41
	 * @since v2.1.3
	 * @param merchantCode
	 * @param busiId
	 * @param type
	 * @param amount
	 * @param orderId
	 * @param url 通知路径
	 * @param rspCode
	 * @param rspMsg
	 */
	@Async
	private void generateNotifyTask(String merchantCode, String busiId, FuiouBusiTypeEnum type, long amount, String orderId, String url, int rspCode,
			String rspMsg) {
		final String op = "ChargeInnerServiceImpl.generateNotifyTask";
		logger.info(Log.op(op).msg("生成通知任务").kv("busiId", busiId).toString());
		try {
			AmountRspParamsVO params = new AmountRspParamsVO();
			params.setOrderId(orderId);
			params.setRspCode(rspCode);
			params.setRspMsg(rspMsg);
			params.setBusiId(busiId);
			params.setAmount(amount);

			YYPayApiReq2<AmountRspParamsVO> req = new YYPayApiReq2<>();
			req.setMerchantCode(merchantCode);
			req.setSign(payCommonService.getSign(merchantCode, params));
			req.setParams(params);

			fuiouDepositCommonService.saveNotifyTask(merchantCode, orderId, busiId, type, url, FastJsonUtil.toJson(req), null, null);
		} catch (Exception e) {
			logger.error(Log.op("ChargeInnerServiceImpl.generateNotifyTask").msg("封装同步结果异步通知任务异常").kv("FuiouCharge.busiId", busiId).toString(), e);
		}
	}

	@Override
	public FuiouChargeVO queryResult(String busiId) {
		final String op = "ChargeInnerServiceImpl.queryResult";
		FuiouCharge po = fuiouChargeDao.selectByBusiId(busiId);
		if (po == null) {
			logger.error(Log.op(op).msg("查询充值结果，根据业务主键查询订单，订单不存在").kv("busiId", busiId).toString());
			throw PayExceptionCode.ERROR_ILL_PARAMETER.expMsg("FuiouCharge不能为空");
		}

		FuiouChargeVO vo = FuiouChargeVO.newInstantce(po);
		if (!vo.isQuery()) {
			// 如果订单,已经出结果，不支持查询，则直接返回
			return vo;
		}

		// 请求富友接口查询充值结果
		PayRspCodeVO result = fuiouDepositService.chargeQuery(po);

		String state = FuiouDepositStateEnum.FAIL.getValue();

		if (PayExceptionCode.SUCCESS.isCode(result.getCode())) {
			state = FuiouDepositStateEnum.SUCCESS.getValue();
		} else if (PayExceptionCode.WARN_REQ_TIME_OUT.isCode(result.getCode()) || PayExceptionCode.TO_CONFIRM.isCode(result.getCode())
				|| PayExceptionCode.QUERY_ERROR.isCode(result.getCode())) {
			// 如果请求超时，或者待确认状态，或者查询异常，查询订单不存在， 则更新状态为处理中，等待下一次查询
			state = FuiouDepositStateEnum.DEALING.getValue();
		} else if (PayExceptionCode.ORDER_NOT_FOUND.isCode(result.getCode())) {
			//如果查询订单不存在，根据业务，不变更订单状态，因为富友存管存在查询报文为空，但是实际存在的场景，等待下一次查询
			return vo;
		}

		if (StringUtils.equals(state, po.getState())) {
			// 如果状态一致，则不需要更新
			return vo;
		}

		// 更新充值状态
		int i = fuiouChargeDao.updateState(po.getBusiId(), state, po.getState(), result.getCode(), result.getDesc(), DateUtil.getCurrentDateTime());

		if (i > 0) {
			// 更新充值状态命中，则设置快照类充值状态，并返回
			po.setState(state);
			po.setRspCode(result.getCode());
			po.setRspMsg(result.getDesc());
			return vo;
		}

		// 如果没有命中，则订单可能存在并发的情况，查询订单信息，并返回
		po = fuiouChargeDao.selectByBusiId(po.getBusiId());

		return FuiouChargeVO.newInstantce(po);
	}

	@Override
	public RedirectFormVO<FuiouTransferChargeFormVO> getTransfer(FuiouChargeVO vo) {
		FuiouCharge po = vo.getPo();
		RedirectFormVO<FuiouTransferChargeFormVO> form = fuiouDepositService.getTransferChargeForm(po);

		// 更新转账充值订单状态为待确认
		int i = fuiouChargeDao.updateState(po.getBusiId(), FuiouDepositStateEnum.ACCEPTED.getValue(), po.getState(),
				PayExceptionCode.TO_CONFIRM.getCode(), PayExceptionCode.TO_CONFIRM.getDesc(), DateUtil.getCurrentDateTime());

		if (i <= 0) {
			// 如果更新订单状态没有命中的话，说明订单状态已经变更，提示异常
			FuiouCharge fuiouCharge = fuiouChargeDao.selectByBusiId(po.getBusiId());
			throw new PayException(fuiouCharge.getRspCode(), fuiouCharge.getRspMsg());
		}

		return form;
	}

	@Override
	public FuiouCharge parseTransferBackResult(String merchantCode, TransferChargeBackReq req) {
		String op = "ChargeInnerServiceImpl.parseTransferBackResult";

		// 解析请求的合法
		boolean isSign = fuiouDepositService.checkSignRspResult(merchantCode, req, req.getSignature());
		if (!isSign) {
			throw PayExceptionCode.ERROR_SIGN_FAIL.exp();
		}

		// 根据业务主键查询订单信息
		FuiouCharge po = fuiouChargeDao.selectByBusiId(req.getMchnt_txn_ssn());
		if (po == null) {
			logger.error(Log.op(op).msg("富友转账充值同步结果回调，订单不存在").kv("busiId", req.getMchnt_txn_ssn()).toString());
			throw PayExceptionCode.ERROR_ILL_PARAMETER.exp();
		}
		//
		// FuiouChargeVO vo = FuiouChargeVO.newInstantce(po);
		// if (vo.isResult()) {
		// // 如果订单是受理成功则直接返回
		// logger.info(Log.op(op).msg("富友转账充值同步结果回调，订单已经出结果，不再处理").kv("busiId", po.getBusiId()).toString());
		// return vo.getPo();
		// }
		//
		// // 判断同步请求金额和订单金额不一致
		// boolean isExpAmount = false;
		// if (req.getAmt() != po.getAmount().longValue()) {
		// // 请求订单金额不一致
		// isExpAmount = true;
		// logger.error(Log.op(op).msg("富友转账充值同步结果回调,请求金额和订单金额不一致").kv("busiId", po.getBusiId()).kv("orderAmount", po.getAmount())
		// .kv("reqAmount", req.getAmt()).toString());
		// }
		//
		// // 解析富友返回响应码
		// FuiouDepositStateEnum state = FuiouDepositStateEnum.FAIL;
		// PayRspCodeVO payRspCode = fuiouDepositService.converToPayRspCode(req.getResp_code());
		// int rspCode = payRspCode.getCode();
		// String rspMsg = payRspCode.getDesc();
		// if (PayExceptionCode.SUCCESS.isCode(payRspCode.getCode())) {
		//
		// // 如果响应结果和订单金额不一致，则返回成功的异常响应码
		// state = FuiouDepositStateEnum.SUCCESS;
		// if (isExpAmount) {
		// // 请求订单金额不一致
		// rspCode = PayExceptionCode.SUCCESS_EXCEPTION.getCode();
		// rspMsg = PayExceptionCode.SUCCESS_EXCEPTION.getDesc();
		// }
		// }
		//
		// // 订单存在web返回状态是超时的，异步通知是成功的场景
		// int i = fuiouChargeDao.updateState(po.getBusiId(), state.getValue(), po.getState(), rspCode, rspMsg, DateUtil.getCurrentDateTime());
		//
		// // 如果更新状态没有命中，则状态可能是并发,则重新查询一次订单信息
		// if (i <= 0) {
		// logger.warn(Log.op(op).msg("富友转账充值页面回跳,更新状态没有成功。").kv("busiId", po.getBusiId()).kv("toState", state.getValue())
		// .kv("origState", po.getState()).toString());
		// return fuiouChargeDao.selectByBusiId(req.getMchnt_txn_ssn());
		// }
		//
		// po.setRspCode(rspCode);
		// po.setRspMsg(rspMsg);
		// po.setState(state.getValue());
		//
		// // 生成一个同步结果的异步通知
		// generateNotifyTask(po.getMerchantCode(), po.getBusiId(), FuiouBusiTypeEnum.parse(po.getType()), po.getAmount(), po.getOrderId(),
		// po.getNotifyUrl(), rspCode, rspMsg);
		//
		// return po;

		return parseResult(req.getResp_code(), req.getRem(), req.getAmt(), po);
	}

	/**
	 * 解析富友存管结果
	 * 
	 * @author buyi
	 * @date 2018-04-03 19:13:22
	 * @since v2.1.3
	 * @param mchntTxnSsn
	 * @param respCode
	 * @param rem
	 * @param amt
	 * @return
	 */
	private FuiouCharge parseResult(String respCode, String rem, long amt, FuiouCharge po) {
		final String op = "ChargeInnerServiceImpl.parseResult";

		FuiouChargeVO vo = FuiouChargeVO.newInstantce(po);
		// if (vo.isResult()) {
		// // 如果订单是受理成功则直接返回
		// logger.info(Log.op(op).msg("富友转账充值结果回调，订单已经出结果，不再处理").kv("busiId", po.getBusiId()).toString());
		// return vo.getPo();
		// }
		// 如果已经生成异步通知,且订单已经出结果，则直接返回
		if (YesNoEnum.YES.isValue(vo.getPo().getIsNotify()) && vo.isResult()) {
			logger.info(Log.op(op).msg("富友转账充值异步结果回调，is_notify已经通知，不再处理").kv("busiId", po.getBusiId()).toString());
			return vo.getPo();
		}

		// 判断同步请求金额和订单金额不一致
		boolean isExpAmount = false;
		if (amt != po.getAmount().longValue()) {
			// 请求订单金额不一致
			isExpAmount = true;
			logger.error(Log.op(op).msg("富友转账充值结果回调,请求金额和订单金额不一致").kv("busiId", po.getBusiId()).kv("orderAmount", po.getAmount()).kv("reqAmount", amt)
					.toString());
		}

		// 解析富友返回响应码
		FuiouDepositStateEnum state = FuiouDepositStateEnum.FAIL;
		PayRspCodeVO payRspCode = fuiouDepositService.converToPayRspCode(respCode);
		int rspCode = payRspCode.getCode();
		String rspMsg = payRspCode.getDesc();
		if (PayExceptionCode.SUCCESS.isCode(payRspCode.getCode())) {

			// 如果响应结果和订单金额不一致，则返回成功的异常响应码
			state = FuiouDepositStateEnum.SUCCESS;
			if (isExpAmount) {
				// 请求订单金额不一致
				rspCode = PayExceptionCode.SUCCESS_EXCEPTION.getCode();
				rspMsg = PayExceptionCode.SUCCESS_EXCEPTION.getDesc();
			}
		}

		// 订单存在web返回状态是超时的，异步通知是成功的场景
		int i = fuiouChargeDao.updateNotifyState(po.getBusiId(), state.getValue(), po.getState(), rspCode, rspMsg);

		// 如果更新状态没有命中，则状态可能是并发,则重新查询一次订单信息
		if (i <= 0) {
			logger.warn(Log.op(op).msg("富友转账充值通知,更新状态没有成功。").kv("busiId", po.getBusiId()).kv("toState", state.getValue())
					.kv("origState", po.getState()).toString());
			return fuiouChargeDao.selectByBusiId(po.getBusiId());
		}

		po.setRspCode(rspCode);
		po.setRspMsg(rspMsg);
		po.setState(state.getValue());

		// 生成一个同步结果的异步通知
		generateNotifyTask(po.getMerchantCode(), po.getBusiId(), FuiouBusiTypeEnum.parse(po.getType()), po.getAmount(), po.getOrderId(),
				po.getNotifyUrl(), rspCode, rspMsg);

		return po;
	}

	@Override
	public FuiouCharge doProtocolSignRecharge(FuiouCharge fuiouCharge) {

		// 更新订单状态为处理中
		int i = fuiouChargeDao.updateStateFromOrigState(fuiouCharge.getBusiId(), FuiouDepositStateEnum.DEALING.getValue(),
				FuiouDepositStateEnum.INI.getValue(), PayExceptionCode.PROCESSING.getCode(), PayExceptionCode.PROCESSING.getDesc());
		if (i <= 0) {
			// 如果订单更新没有命中，则订单状态已经变更，则查询订单结果，直接返回

			FuiouCharge fuiouChargeNew = fuiouChargeDao.selectByBusiId(fuiouCharge.getBusiId());
			return fuiouChargeNew;
		}

		FuiouDepositStateEnum state = FuiouDepositStateEnum.FAIL;
		// 调用富友存管协议充值
		PayRspCodeVO payRspCode = fuiouDepositService.doProtocolSignRecharge(fuiouCharge);
		if (PayExceptionCode.SUCCESS.isCode(payRspCode.getCode())) {
			state = FuiouDepositStateEnum.SUCCESS;
		} else if (PayExceptionCode.isToConfirm(payRspCode.getCode())) {
			state = FuiouDepositStateEnum.ACCEPTED;
		} else if (PayExceptionCode.isTimeout(payRspCode.getCode())) {
			state = FuiouDepositStateEnum.TIMEOUT;

			// 保存主动查询任务
			fuiouDepositCommonService.saveQueryTask(fuiouCharge.getMerchantCode(), fuiouCharge.getBusiId(), FuiouBusiTypeEnum.CHARGE_QUERY);
		}

		// 更新订单状态
		fuiouChargeDao.updateStateFromOrigState(fuiouCharge.getBusiId(), state.getValue(), FuiouDepositStateEnum.DEALING.getValue(),
				payRspCode.getCode(), payRspCode.getDesc());

		fuiouCharge.setState(state.getValue());
		fuiouCharge.setRspCode(payRspCode.getCode());
		fuiouCharge.setRspMsg(payRspCode.getDesc());

		return fuiouCharge;
	}

	@Override
	public FuiouChargeTransferVO doTransfer(FuiouChargeVO vo) {
		final String op = "ChargeInnerServiceImpl.doTransfer";

		FuiouCharge po = vo.getPo();
		// 更新订单处理中
		int i = fuiouChargeDao.updateState(po.getBusiId(), FuiouDepositStateEnum.DEALING.getValue(), po.getState(),
				PayExceptionCode.DEALING.getCode(), PayExceptionCode.DEALING.getDesc(), DateUtil.getCurrentDateTime());

		if (i <= 0) {
			logger.warn(Log.op(op).msg("转账充值，更新订单状态为处理没有命中,则直接返回结果").kv("busiId", po.getBusiId()).toString());
			// 如果更新订单状态没有命中的话，说明订单状态已经变更，提示异常
			FuiouCharge fuiouCharge = fuiouChargeDao.selectByBusiId(po.getBusiId());
			FuiouChargeTransfer fuiouChargeTransfer = fuiouChargeTransferDao.select(po.getBusiId());
			return FuiouChargeTransferVO.newInstance().fuiouCharge(fuiouCharge).fuiouChargeTransfer(fuiouChargeTransfer);
		}

		String fromState = FuiouDepositStateEnum.DEALING.getValue();

		// 发起转账充值
		PayRspCodeVO payRspCodeVO = fuiouDepositService.doTransfer(po);

		String toState = FuiouDepositStateEnum.FAIL.getValue();
		// 委托充值无页面接口，交易结果以异步通知为准
		// if (PayExceptionCode.SUCCESS.isCode(payRspCodeVO.getCode()) || PayExceptionCode.isTimeout(payRspCodeVO.getCode())
		// || PayExceptionCode.isToConfirm(payRspCodeVO.getCode())) {
		if (PayExceptionCode.SUCCESS.isCode(payRspCodeVO.getCode())) {
			// 如果响应结果为成功，超时，或者是待确认状态，则更新订单状态为受理成功
			// 转账充值无页面接口，同步请求需要返回充值码和响应的银行卡信息，所以，同步请求结果，如果不是成功即为失败。不设置中间状态。

			toState = FuiouDepositStateEnum.ACCEPTED.getValue();
		}

		int updateState = fuiouChargeDao.updateState(po.getBusiId(), toState, fromState, payRspCodeVO.getCode(), payRspCodeVO.getDesc(),
				DateUtil.getCurrentDateTime());

		if (updateState <= 0) {
			// 如果更新订单状态没有命中的话，说明订单状态已经变更，提示异常
			logger.error(
					Log.op(op).msg("转账充值，更新订单同步操作结果，没有命中").kv("busiId", po.getBusiId()).kv("toState", toState).kv("fromState", fromState).toString());

			FuiouCharge fuiouCharge = fuiouChargeDao.selectByBusiId(po.getBusiId());
			FuiouChargeTransfer fuiouChargeTransfer = fuiouChargeTransferDao.select(po.getBusiId());

			return FuiouChargeTransferVO.newInstance().fuiouCharge(fuiouCharge).fuiouChargeTransfer(fuiouChargeTransfer);
		}

		// 保存转账充值信息
		FuiouChargeTransfer fuiouChargeTransfer = saveChargeTransfer(po, (TransferChargePlain) payRspCodeVO.getObj());

		po.setState(toState);
		po.setRspCode(payRspCodeVO.getCode());
		po.setRspMsg(payRspCodeVO.getDesc());

		return FuiouChargeTransferVO.newInstance().fuiouCharge(po).fuiouChargeTransfer(fuiouChargeTransfer);
	}

	/**
	 * 保存转账充值扩展信息
	 * 
	 * @author buyi
	 * @date 2018-06-05 16:15:16
	 * @since v2.1.1
	 * @param busiId
	 * @param obj
	 * @return
	 */
	private FuiouChargeTransfer saveChargeTransfer(FuiouCharge po, TransferChargePlain plain) {
		final String op = "ChargeInnerServiceImpl.saveChargeTransfer";

		// FuiouChargeTransfer fuiouChargeTransfer = new FuiouChargeTransfer();
		if (plain == null) {
			logger.warn(Log.op(op).msg("保存转账充值扩展信息，富友存管响应信息为空返回空报文 ").kv("busiId", po.getBusiId()).toString());
			return null;
		}

		// 同步请求异常场景下，plain的相关参数为空
		if (StringUtils.isBlank(plain.getChgCd()) || StringUtils.isBlank(plain.getFyAccNo()) || StringUtils.isBlank(plain.getFyBank())
				|| StringUtils.isBlank(plain.getFyBankBranch())) {
			logger.warn(Log.op(op).msg("保存转账充值扩展信息，富友存管响应信息为关键信息为空，不保存 ").kv("busiId", po.getBusiId()).toString());
			return null;
		}

		FuiouChargeTransfer fuiouChargeTransfer = new FuiouChargeTransfer();
		try {
			fuiouChargeTransfer.setBusiId(po.getBusiId());
			fuiouChargeTransfer.setMerchantCode(po.getMerchantCode());
			fuiouChargeTransfer.setOrderId(po.getOrderId());
			fuiouChargeTransfer.setChargeCode(plain.getChgCd());
			fuiouChargeTransfer.setInCardNoCip(CryptUtil.encrypt(plain.getFyAccNo()));
			// 修改入账用户名
			// fuiouChargeTransfer.setInBankName(plain.getFyBank());
			fuiouChargeTransfer.setInBankName(plain.getFyAccNm());
			fuiouChargeTransfer.setInBankBranceName(plain.getFyBankBranch());

			fuiouChargeTransferDao.insert(fuiouChargeTransfer);

			return fuiouChargeTransfer;
		} catch (Exception e) {
			logger.error(Log.op(op).msg("保存转账充值扩展信息异常").kv("busiId", po.getBusiId()).kv("FuiouChargeTransfer", fuiouChargeTransfer).toString(), e);
		}

		return null;
	}

	@Override
	public TransferChargeRsp getTransferChargeRsp(FuiouCharge fuiouCharge, FuiouChargeTransfer fuiouChargeTransfer) {
		// 封住响应参数
		if (fuiouChargeTransfer == null) {
			return null;
		}

		TransferChargeRsp transferChargeRsp = TransferChargeRsp.newInstance().orderId(fuiouCharge.getOrderId())
				.chargeCode(fuiouChargeTransfer.getChargeCode()).inBankName(fuiouChargeTransfer.getInBankName())
				.inBankBranceName(fuiouChargeTransfer.getInBankBranceName());
		try {
			transferChargeRsp.inCardNo(CryptUtil.decrypt(fuiouChargeTransfer.getInCardNoCip()));
		} catch (Exception e) {
			logger.error(Log.op("ChargeWithdrawApiController.transferCharge").msg("转账充值，封装响应参数。解密银行卡号异常")
					.kv("busiId", fuiouChargeTransfer.getBusiId()).toString());
		}

		return transferChargeRsp;
	}

	@Override
	public TransferChargeRsp getTransferChargeRsp(FuiouCharge fuiouCharge) {
		FuiouChargeTransfer fuiouChargeTransfer = fuiouChargeTransferDao.select(fuiouCharge.getBusiId());
		return getTransferChargeRsp(fuiouCharge, fuiouChargeTransfer);
	}

	/**
	 * 查询充值订单结果
	 * 
	 * @author buyi
	 * @date 2017-09-25 15:41:43
	 * @since v2.0.0
	 * @param vo
	 */
	// private FuiouChargeVO queryResult(FuiouChargeVO vo) {
	// if (!vo.isQuery()) {
	// // 如果订单,已经出结果，不支持查询，则直接返回
	// // 如果入参vo和出参FuiouChargeVO存在编辑的情况，则该方法不适用，需要做深度copy
	// return FuiouChargeVO.newInstantce(vo.getPo());
	// }
	//
	// FuiouCharge po = vo.getPo();
	//
	// PayRspCodeVO result = fuiouDepositService.chargeQuery(po);
	//
	// String state = FuiouDepositStateEnum.FAIL.getValue();
	//
	// if (PayExceptionCode.SUCCESS.isCode(result.getCode())) {
	// state = FuiouDepositStateEnum.SUCCESS.getValue();
	// } else if (PayExceptionCode.WARN_REQ_TIME_OUT.isCode(result.getCode())) {
	// // 如果请求超时，则更新状态为处理中
	// state = FuiouDepositStateEnum.DEALING.getValue();
	// }
	//
	// if (StringUtils.equals(state, po.getState())) {
	// // 如果状态一致，则不需要更新
	// // 如果入参vo和出参FuiouChargeVO存在编辑的情况，则该方法不适用，需要做深度copy
	// return FuiouChargeVO.newInstantce(vo.getPo());
	// }
	//
	// int i = fuiouChargeDao.updateState(po.getBusiId(), state, po.getState(), result.getCode(), result.getDesc(), DateUtil.getCurrentDateTime());
	//
	// if (i > 0) {
	// po.setState(state);
	// po.setRspCode(result.getCode());
	// po.setRspMsg(result.getDesc());
	// // 如果入参vo和出参FuiouChargeVO存在编辑的情况，则该方法不适用，需要做深度copy
	// return FuiouChargeVO.newInstantce(po);
	// }
	//
	// // 如果没有命中，则订单可能存在并发的情况，查询订单信息，并返回
	// po = fuiouChargeDao.selectByBusiId(po.getBusiId());
	//
	// return FuiouChargeVO.newInstantce(po);
	// }
}
